// vuex所在目录名称一般为store
// vuex是一个插件,安装命令为: npm install vuex --save
// 把需要多个组件共享的变量全部存储在一个对象里面
import Vue from 'vue'
import Vuex from 'vuex'
//导入常量
import {INCREMENT} from '@/store/mutations-type'

//安装插件
Vue.use(Vuex)

const moduleA = {
    state: {
      name: '苏州大学'
    },
    mutations: {
      updateName(state,payload){
        state.name = payload
      }
    },
    actions: {
      //context同时包含根中的内容,可以根据需求取用
      aUpdateName(context){ //这里的context不再是store对象,在commit时,只会调用自己的mutations中的方法
        setTimeout(() => {
          console.log(context)
          context.commit('updateName','王小二')
        },1000)
      }
    },
    getters: {
      fullName1(state){
        return state.name + ':养天地正气,法古今完人'
      },
      fullName2(state,getters){
        return getters.fullName1 + ':说的很有道理'
      },
      fullName3(state,getters,rootState){ //调用store中的state,在模块中,getters可以有第三个参数
        return getters.fullName2 + rootState.counter
      }
    }
}

/*
  单一状态树: 一个项目只有一个Store对象
  创建对象
    state: 保存状态
 */
const store = new Vuex.Store({
  state: {
    counter: 1000,
    students: [
      {id: 110, name: 'why', age: 18},
      {id: 111, name: 'kobe', age: 24},
      {id: 112, name: 'james', age: 30},
      {id: 113, name: 'curry', age: 10}
    ],
    info: {
      name: 'kobe',
      age: 40,
      heigth: 1.98
    }
  },
  mutations:{
    /*
      Vuex的store状态的更新唯一方式: 提交Mutation
      默认有一个参数为state,即上面的state对象
      调用时可以携带一些额外的参数,如果参数不是一个,则通常会以对象的形式传递
      在mutation中,如果定义了很多事件类型(也就是其中的方法名称),在调用时可能会出错
      所以推荐使用常量替代Mutation事件的类型
     */
    [INCREMENT](state){ //方法名使用的是导入的常量,好处在于调用该方法时也可以使用该常量,防止手写发生错误,推荐使用这种方式
      state.counter++
    },
    decrement(state){
      state.counter--
    },
    //可以同时定义参数,在由commit调用时同时传入
    incrCount(state,count){
      // 1、普通的提交风格参数就是count
      // state.counter += count

      // 2、特殊的提交风格参数是一个对象
      console.log(count)
      state.counter += count.count
    },
    //如果参数不是一个,则通常会以对象的形式传递
    addStudent(state,stu){
      state.students.push(stu)
    },
    updateInfo(state){
      // Vuex的store中的state是响应式的,当state中的数据发生改变时,Vue组件会自动更新,前提是在store中初始化好所需的属性
      state.info.name = '苏州大学'
      
      // 后添加的属性是不会添加到响应式系统中的,所以无法在界面上实时响应
      // state.info['address'] = '洛杉矶'

      // 如果确实需要新添加的属性是响应式的,可以使用Vue提供的方法
      // Vue.set(state.info, 'address', '洛杉矶')

      // 当需要删除对象中的属性时,该方式做不到响应式
      // delete state.info.age

      // 当需要删除对象中的属性时,如果需要做到响应式,可以使用Vue提供的方法
      // Vue.delete(state.info,'age')
    }
  },
  actions: {
    /*
      Mutation中的方法必须是同步方法,如果是异步操作那么devtools将不能很好的追踪这个操作什么时候会被完成
      如果确实希望在Vuex中进行一些异步操作,比如网络请求,则使用Action
      Action类似于Mutation,但是是用来代替Mutation进行异步操作的
     */
    aUpdateInfo(context,payload){ //默认参数为context,即store对象,同时可以定义第二个参数,用于携带参数
      //如果需要修改state中的参数,注意不要直接修改,而是通过Mutation进行更改,切忌不可跳过Mutation
      // setTimeout(() => {
        // console.log(payload)
        // context.commit('updateInfo') //调用Mutation中的方法

        //调用成功后,通知调用的地方(这种方式不优雅,不推荐使用)
      //   console.log(payload.message)
      //   payload.success()
      // },2000)

      // 通知调用的地方,更加优雅的解决方式
      return new Promise((resolve,reject) => {
        setTimeout(() => {
          context.commit('updateInfo')
          console.log(payload)

          //成功后调用relosve()
          resolve('调用成功')
        },2000)
      }) //调用成功后的.then操作在调用使用
    }
  },
  getters: {
    //方法: 默认有一个参数为state,即上面的state对象
    powerCounter(state){
      return state.counter * state.counter
    },
    more20stu(state){
      return state.students.filter(s => s.age > 20)
    },
    //getters中的方法可以有第二个参数(本身),即可以获取getters中其他方法的返回值
    more20stuLength(state,getters){ 
      return getters.more20stu.length
    },
    //当geeters中的方法需要在调用时传入一些参数时,可以返回一个函数
    moreAgeStu(state){
      // return function(age){
      //   return state.students.filter(s => s.age > age)
      // }

      //箭头函数写法
      return age => {
        return state.students.filter(s => s.age > age)
      }
    }
  },
  modules: {
    a: moduleA
  }
})

//导出对象
export default store
